home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 90 / CD Actual 90.iso / Software3D / VirtualLight / VLight1.3win32.exe / Bin / vlightexport210.py < prev    next >
Encoding:
Python Source  |  2002-10-07  |  24.3 KB  |  614 lines

  1. #
  2. #    bruteforce (Tm) VirtauLight exporter for Blender v2.12
  3. #    version 1.2
  4. #    by jano lukac, jedovaty@yahoo.com
  5.  
  6. #    The latest version can be found here:
  7. #    http://www.drlukac.com/jano/fridge/vlightexport.py
  8.  
  9. import Blender210
  10. import os, re, sys
  11. from math import *
  12. from string import lower
  13.  
  14.  
  15. #
  16. # Quick start:
  17. #
  18. #        1. Modify the two variables below: savePath and outFile.
  19. #            Please make sure savePath exists, and do not put extensions
  20. #            to the outFile
  21. #        2. Open this in Blender (if you haven't done so already)
  22. #        3. Press alt-p over this script in Blender
  23. #        4. Go to savePath dir and type vlight <outFile> -a 8
  24. #        5. While you wait, read through these comments and the VirtuaLight
  25. #            documentation
  26. #        6. For the "GI" look, use a hemi-lamp with Y rotations:
  27. #            -90 <= rotY => 90
  28. #            Read the Lights section below for more info
  29.  
  30. savePath = "c:/tmp/vlight/"
  31. outFile = "file"
  32.  
  33. #
  34. # Comments, Docs, Notes
  35. #
  36. #    I highly recommend you edit the output .vib and .vs files.
  37. #    See a little further down for help with lights.
  38.  
  39. #    I expect you to read these comments.. if you don't, well, TS.
  40.  
  41. #    Running this script in blender will produce in your savePath:
  42. #        1. $outFile.vib        # the scene
  43. #        2. $outFile.vs        # materials
  44. #        3. $filePath/Meshes/$mesh$appendor.vib        # mesh structure
  45.  
  46. #    Python notes:
  47. #        If you use python > 2.0, change the "re" module to "pre" at all
  48. #            occurances (i.e. search and replace).
  49.  
  50. #    Notes on supported Blender Objects
  51. #    Camera:
  52. #        If everything seems a bit skewed, change the FOV setting in this script.
  53. #    Meshes:
  54. #        All meshes export as TriangularPatches now, to maintain UV coords.
  55. #        If you have stray vertices in a mesh (i.e. vertices but no face), you
  56. #            will risk the chance of either having stray faces in the output
  57. #            VIB or an empty Solid[] structure.  The empty Solid[] struct
  58. #            will also result with a "Parse Error".  I currently have no way
  59. #            to fix this, so you will have to do it manually.
  60. #        If you get weird results, try to first "apply size/rot" to the mesh.
  61. #        If you get a "parse error" in your .vib files, first check for an
  62. #            empty Solid[] structure in the vib, then try renaming the
  63. #            mesh in Blender.. stuff like "Box", "Plane", and "Sphere" are
  64. #            reserved in VirtuaLight, and will cause these errors.
  65. #            I made a basic attempt to fix this by prepending a "X" to every
  66. #            name.  It's ugly, but it works -- can be changed in the Optional
  67. #            Mods sections below.
  68. #        SetSmooth works on both triangles and qauds; however, to make it work,
  69. #            I had to manually convert quads to tris.  If you don't trust this,
  70. #            please convert your mesh to triangles first.
  71. #        If you have SetSmooth on quads, and have UV textures, then UV Textures
  72. #            will be exported, but if you have problems, ctrl-t the mesh first.
  73. #    Materials:
  74. #        I default to PlainSurfaces, and just use basic settings, because,
  75. #            although the settings are available in blender, I cannot get to
  76. #            them via python.  You can manually transcribe them.
  77. #        If you want to use textures, use FaceSelect mode in blender
  78. #            to assign UV coordinates.  Then read how to apply textures
  79. #            in the VirtauLight sepcifications PDF included with said program
  80. #        No access to blender's SpTr yet, so use alpha to determine Kt.  I
  81. #            default to an Index of Refraction to 1.3333 (glass), and use the
  82. #            material "Mir" RGB sliders to affect the colors.
  83. #        You can change specularity type in the Optional mods section below
  84. #    Lights:
  85. #        This is the fun one.  VirtuaLight has SO MANY lights, it's not even
  86. #            funny.  I chose the corresponding lights based on functionality,
  87. #            but *NOT* on name -- it's a bit confusing at fist, but you'll get
  88. #            used to it. Here is how I translate between VirtuaLight and Blender:
  89. #                AreaLight(bulb):    Lamp + sphere
  90. #                AreaLight(plane):    Lamp + square (not implemented yet)
  91. #                BlackHole:    Lamp + negative
  92. #                DirectionalLight:    Sun
  93. #                PointLight:    Lamp
  94. #                SkyLight+Sunlight:    Hemi
  95. #                SpotLight:    Spot
  96. #            Note that "ClipEnd" will adjust VirtualLight's Falloff variable
  97. #                (i.e. I couldn't find a suibtable value in blender)
  98. #        The QUAD button in lights (f2) will make certain lamps Quadratic
  99. #            instead of linear.
  100. #        SunLight can be incredibly bright, consider commenting it out in the
  101. #            scene vib file and using other lights instead.  The Dist value
  102. #            affects the SunLight shadow; energy affects SkyLight intensity.
  103. #        BlackHole element "Density" is set by lamp's Distance in blender.
  104. #
  105. #    KnownBugs with output mechanism:
  106. #        The script itself should always work; however, the ouput may cause
  107. #            parse errors with VirtuaLight (I handle most of them).
  108. #        Stray vertices will cause either a parse error (due to an empty Solid[]
  109. #            or extra faces in the output.  Cannot be fixed without change in
  110. #            Blender's python API.
  111. #        I *think* VirtuaLight will work properly if Material and Mesh names
  112. #            are identical.  If you want to be on the safe side, make sure
  113. #            all names in blender are unique before you export.
  114. #
  115. #    Changes since 1.1:
  116. #        - added initialization for abNormals variable, as it caused fluke
  117. #            in some cases.  Thanks to bladesman for finding it.
  118. #    Changes since 1.0:
  119. #        - allow for unsmoothed quads and tris to retain UV coords by exporting
  120. #            all mesh as TriangularPatches instead of Polygon.
  121. #        - divide by zero fix
  122. #        - documentation fix
  123. #
  124. #    Todo:
  125. #        - Possible nurbs (blender api pending?)
  126. #        - Possible metaballs (blender api pending?)
  127. #        - Mini gui to modify stuff like lights, change mesh type, etc.
  128. #        - Handle basic animations
  129. #        - Someone with programming experience could convert some
  130. #            blender procedural textures to VirtuaLight shaders
  131. #        - Find work.. if anyone needs a Sysadmin or Network Admin in
  132. #            the southern california area, please contact me ;]
  133. #
  134.  
  135.  
  136. #
  137. # Optional Modifications
  138. #
  139. # I default rounding numbers to 4.  If you want more precision, change this
  140. # But you NEED rounding, otherwise you might get numbers with "e" in them
  141. # and VirtuaLight doesn't handle that.
  142. r = 4
  143.  
  144. # Change "specType" to tell what type of Specular Highlights you want default
  145. # in your materials.  I default to "Phong" because I like to say,
  146. # "BUI TUI PHONG!"
  147. specType = 0
  148. specHighlight = ["Phong", "Blinn", "Cook", "Reitz", "Gaussian"]
  149.  
  150. # Change append symbol.. use only [a-z][A-Z][0-9] and/or _
  151. # This symbol is appended to all meshes and materials
  152. appendor = "X"
  153.  
  154.  
  155. #
  156. # read further.. if you dare [maniacle laughter]
  157. #
  158.  
  159.  
  160. #
  161. # sub functions - yes, I come from PERL
  162. #
  163. def multiply3x3(A, B):
  164.     C = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
  165.     for i in range(3):
  166.         for j in range(3):
  167.             for k in range(3):
  168.                 C[i][j] = C[i][j] + A[i][k]*B[k][j]
  169.     return C
  170.  
  171. def multiply3x1(A, B):
  172.     C = [0,0,0]
  173.     for i in range(3):
  174.         for j in range(3):
  175.             C[i] = C[i] + A[i][j]*B[j]
  176.     return C
  177.  
  178. def parallelVector(rotX, rotY, rotZ, oAxis):
  179.     # convert to radians
  180.     rotX = rotX * pi/180
  181.     rotY = rotY * pi/180
  182.     rotZ = rotZ * pi/180
  183.     # counterclockwise rotations about given axis through angle)
  184.     Tx = [[1, 0, 0], [0, cos(rotX), -sin(rotX)], [0, sin(rotX), cos(rotX)]]
  185.     Ty = [[cos(rotY), 0, sin(rotY)], [0, 1, 0], [-sin(rotY), 0, cos(rotY)]]
  186.     Tz = [[cos(rotZ), -sin(rotZ), 0], [sin(rotZ), cos(rotZ), 0], [0, 0, 1]]
  187.     Tm = multiply3x3(multiply3x3(Tz, Ty), Tx)
  188.     return multiply3x1(Tm, oAxis)
  189.  
  190. def calcNormal(face, verts, n):
  191.     # If it's a quad, calculate normal from diagonal instead
  192.     # Assume verts are sorted in circular fasion (i.e. next to each other)
  193.     m = (3 * n) | 1    # when n=0 (tri), m=1; when n=1 (quad), m=3
  194.     vectorU = [verts[face[0]][0] - verts[face[2]][0],
  195.                verts[face[0]][1] - verts[face[2]][1],
  196.                verts[face[0]][2] - verts[face[2]][2]]
  197.     vectorV = [verts[face[n]][0] - verts[face[m]][0],
  198.                verts[face[n]][1] - verts[face[m]][1],
  199.                verts[face[n]][2] - verts[face[m]][2]]
  200.     normal = [(vectorU[1] * vectorV[2]) - (vectorU[2] * vectorV[1]),
  201.               (vectorU[2] * vectorV[0]) - (vectorU[0] * vectorV[2]),
  202.               (vectorU[0] * vectorV[1]) - (vectorU[1] * vectorV[0])]
  203.     nLength = sqrt((normal[0] ** 2) + (normal[1] ** 2) + (normal[2] ** 2))
  204.     # divide by zero check
  205.     if not nLength: return "stray"
  206.     else: return (normal[0]/nLength, normal[1]/nLength, normal[2]/nLength)
  207.  
  208. def removeDot(name, printResults = 1):
  209.     # Blender automatically names duped objects with "."  Virtual light
  210.     # does not play well with either that or other non-word characters.
  211.     p = re.compile("\W")
  212.     fixedName = p.sub("_", name)
  213.     if p.search(name):
  214.         if printResults:
  215.             print "%s renamed to %s..." % (name, fixedName)
  216.     return fixedName
  217.  
  218. def prepareName(name, list, printResults = 1):
  219.     # I felt bad for not handling reserved names, so this basically takes
  220.     # care of that.  Just prepend a "X" to every name, and if it alread
  221.     # exists, do it again.. hah, my first successful recursive function!
  222.     m = re.compile("(.*?)(%s+$)" % appendor).search(name)
  223.     if m: fixedName = lower(m.group(1)) + m.group(2)
  224.     else: fixedName = lower(name)
  225.     fixedName = "%s%s" % (fixedName, appendor)
  226.     try:
  227.         list.index(fixedName)
  228.         fixedName = prepareName(fixedName, list, printResults)
  229.     except:
  230.         if printResults:
  231.             print "%s renamed to %s..." % (name, fixedName)
  232.     return fixedName
  233.  
  234.  
  235. # variables
  236. meshList = []
  237. lampList = []
  238. materialList = []
  239. fixedMatList = []
  240. fixedMeshList = []
  241.  
  242.  
  243. #
  244. # "Main"
  245. #
  246. scene  = Blender210.getCurrentScene()
  247.  
  248. # Setup Scene VIB File
  249. if not os.path.isdir(savePath):
  250.     print "#\n#\tSorry path %s does not exist" % savePath
  251.     print "#\tPlease make sure the path is there\n#"
  252.     print "You will now see an error message:"
  253. vibFileName = "%s%s.vib" % (savePath, outFile)
  254. VIBFILE = open(vibFileName, "w")
  255. VIBFILE.write("// Scene file converted from Blender by bruteforce\n\n")
  256. VIBFILE.write("Options [\n\tEnableAllLightsIrradiance\n]\n\n")
  257.  
  258. # Setup Material VS File
  259. vsFileName = "%s%s.vs" % (savePath, outFile)
  260. VSFILE = open(vsFileName, "w")
  261. VSFILE.write("// Shader file converted from Blender by bruteforce\n\n")
  262. VSFILE.write("ReadArchive \"statics.vib\"\n\n")
  263.  
  264. # Setup Meshes directory, files handled later
  265. meshPath = "%sMeshes" % (savePath)
  266. if not os.path.isdir(meshPath):
  267.     os.mkdir(meshPath)
  268.     print "%s does not exist, creating" % meshPath
  269.  
  270. #
  271. # camera export
  272. #
  273. try:
  274.     cameraObj = scene.getCurrentCamera()
  275.     camera = Blender210.getCamera(cameraObj.data)
  276.     display = Blender210.getDisplaySettings()
  277.     aspect = display.yResolution / float(display.xResolution)
  278.     print "Writing camera..."
  279.     VIBFILE.write("Camera [\n")
  280.     VIBFILE.write("\t(%s,%s,%s), " % (round(cameraObj.loc[0],r),
  281.                                       round(cameraObj.loc[1],r),
  282.                                       round(cameraObj.loc[2],r)))
  283.     lookAt = parallelVector(cameraObj.rot[0], cameraObj.rot[1], cameraObj.rot[2], (0,0,-1))
  284.     # (a,b,c) = (x,y,z) + t(parallel vector) where t is some factor, I use 1
  285.     lookAt = [cameraObj.loc[0] + lookAt[0], cameraObj.loc[1] + lookAt[1], cameraObj.loc[2] + lookAt[2]]
  286.     VIBFILE.write("(%s,%s,%s), " % (round(lookAt[0],r),
  287.                                     round(lookAt[1],r),
  288.                                     round(lookAt[2],r)))
  289.     upAxis = parallelVector(cameraObj.rot[0], cameraObj.rot[1], cameraObj.rot[2], (0,1,0))
  290.     VIBFILE.write("(%s,%s,%s)\n" % (round(upAxis[0],r),
  291.                                     round(upAxis[1],r),
  292.                                     round(upAxis[2],r)))
  293.     # which FoV is it, dammit!?
  294.     VIBFILE.write("\tFieldOfView %s\n" % (360 * atan(aspect * 16 / camera.Lens) / pi))
  295.     #VIBFILE.write("\tFieldOfView %s\n" % camera.Lens)
  296.     VIBFILE.write("\tFormat(%s,%s)\n"  % (display.xResolution, display.yResolution))
  297.     # negative frame aspect ratio to prevent a mirrored image!
  298.     # Thanks to Stephane Marty (virtualight author!) for this tip
  299.     VIBFILE.write("\tFrameAspectRatio -%s/%s\n" % (display.xResolution, display.yResolution))
  300.     VIBFILE.write("\tClipping(%s,%s)\n" % (round(camera.ClSta,r), round(camera.ClEnd,r)))
  301.     VIBFILE.write("]\n\n")
  302. except:
  303.     print("no camera found, defaulting\n")
  304.     VIBFILE.write("// No camera found, using some made up default\n")
  305.     VIBFILE.write("Camera [ (30,30,0), (0,0,0), (0,1,0) ]\n\n")
  306.  
  307. # separate mesh and lights to nicely organize output files
  308. # Note: materials are accessed different, wait until I'm inside the mesh export
  309. for name in scene.objects:
  310.     if Blender210.isMesh(name):
  311.         meshList.append(name)
  312.     if Blender210.isLamp(name):
  313.         lampList.append(name)
  314.  
  315. #
  316. # lamp export
  317. #
  318. for name in lampList:
  319.     print "Writing lamp %s..." % name
  320.  
  321.     # define lights -- there's prolly a better way to do this
  322.     vlights = ["AreaLight", "BlackHole", "DirectionalLight", "PointLight", "SkyLight", "SpotLight"]
  323.     blights = {"Lamp": 3, "Spot": 5, "Sun": 2, "Hemi": 4}
  324.     lampObj = Blender210.getObject(name)
  325.     lamp = Blender210.getLamp(lampObj.data)
  326.     lampType = blights[lamp.type]
  327.     # note that Lamp Mode will take precedence over Lamp Type
  328.     if lamp.mode[1] == "1": lampType = 0 # sphere->arealight+bulb
  329.     if lamp.mode[7] == "1": lampType = 0 # square->arealight+plane
  330.     if lamp.mode[5] == "1": lampType = 1 # negative
  331.     # begin writing -- some will have to change
  332.     VIBFILE.write("// Lamp: %s\n" % name) # Thanks to JamesK for this one
  333.     if lampType == 1:
  334.         VIBFILE.write("%s (" % vlights[lampType])
  335.         VIBFILE.write("(%s,%s,%s), %s, " % (round(lampObj.loc[0],r),
  336.                                             round(lampObj.loc[1],r),
  337.                                             round(lampObj.loc[2],r),
  338.                                             lamp.Dist))
  339.         VIBFILE.write("'%s,%s,%s'" % (1 - lamp.R, 1 - lamp.G, 1 - lamp.B))
  340.         VIBFILE.write("*%s)\n" % lamp.Energ)
  341.     if lampType == 4:
  342.         VIBFILE.write("%s (" % vlights[lampType])
  343.         VIBFILE.write("%s, " % (lamp.Dist * 5))
  344.         VIBFILE.write("'%s,%s,%s', " % (lamp.R, lamp.G, lamp.B))
  345.         VIBFILE.write("%s)\n" % lamp.Energ)
  346.         # calculate sun light
  347.         if lampObj.rot[1] <= 90 and lampObj.rot[1] >= -90:
  348.             degrees = round(lampObj.rot[1],r)
  349.             hours = 12 - int(degrees / 15)
  350.             minutes = 2 * int(degrees % 30)
  351.             VIBFILE.write("SunLight(%02d:%02d, %s)\n\n" % (hours, minutes, lamp.Dist))
  352.         else: VIBFILE.write("\n")
  353.     else:
  354.         VIBFILE.write("%s [\n" % vlights[lampType])
  355.         # separate the differences
  356.         if lampType == 0:
  357.             if lamp.mode[7] == "0":
  358.                 VIBFILE.write("\tBulb ((%s,%s,%s), %s)\n" % (round(lampObj.loc[0],r),
  359.                                                              round(lampObj.loc[1],r),
  360.                                                              round(lampObj.loc[2],r),
  361.                                                              lamp.Dist))
  362.         elif lampType == 2:
  363.             lightFrom = parallelVector(lampObj.rot[0], lampObj.rot[1], lampObj.rot[2], (0,0,-1))
  364.             VIBFILE.write("\t(%s,%s,%s)\n" % (round(lightFrom[0],r),
  365.                                               round(lightFrom[1],r),
  366.                                               round(lightFrom[2],r)))
  367.         elif lampType == 3:
  368.             VIBFILE.write("\t(%s,%s,%s)\n" % (round(lampObj.loc[0],r),
  369.                                               round(lampObj.loc[1],r),
  370.                                               round(lampObj.loc[2],r)))
  371.         elif lampType == 5:
  372.             VIBFILE.write("\t(%s,%s,%s), " % (round(lampObj.loc[0],r),
  373.                                               round(lampObj.loc[1],r),
  374.                                               round(lampObj.loc[2],r)))
  375.             lightFrom = parallelVector(lampObj.rot[0], lampObj.rot[1], lampObj.rot[2], (0,0,-1))
  376.             VIBFILE.write("(%s,%s,%s), " % (round(lightFrom[0],r),
  377.                                             round(lightFrom[1],r),
  378.                                             round(lightFrom[2],r)))
  379.             VIBFILE.write("%s, " % lamp.SpoSi)
  380.             # NOTE: this value is supposed to be "Falloff," but I couldn't find
  381.             # a suibtable replacement in blender for it -- so using clipEnd for now
  382.             VIBFILE.write("%s, " % lamp.ClipEnd)
  383.             VIBFILE.write("%s\n" % round(lamp.SpoBl,r))
  384.  
  385.         # put all similar attribs together here
  386.         VIBFILE.write("\tIntensity '%s,%s,%s'*%s\n" % (lamp.R, lamp.G, lamp.B, lamp.Energ))
  387.         # This one sets the quadratic thingy -- take a look at
  388.         # equation in blender for the quad1 and quad2 settings,
  389.         # maybe important to add as factor to INTENSITY
  390.         if lamp.mode[0] == "1":
  391.             VIBFILE.write("\tDecay QUADRATIC\n")
  392.         if lamp.mode[6] == "1":
  393.             VIBFILE.write("\tLightingAttributes SHADOW\n")
  394.         elif lamp.mode[6] == "0" and lamp.mode[2] == "0":
  395.             VIBFILE.write("\tLightingAttributes SPECULAR\n")
  396.         if lamp.mode[7] == "0":
  397.             VIBFILE.write("\tMediaInteraction\n")
  398.             if lampType != 5 and lamp.mode[3] == "1":
  399.                 VIBFILE.write("\tGlow %s\n" % lamp.HaInt)
  400.         VIBFILE.write("]\n\n")
  401.  
  402.  
  403. #
  404. # mesh export
  405. #
  406. for name in meshList:
  407.     # Check for empty meshes
  408.     meshObj = Blender210.getObject(name)
  409.     mesh = Blender210.getMesh(meshObj.data)
  410.     faces = mesh.faces
  411.     if not faces: continue
  412.  
  413.     # Check for "." in name, then make sure name is unique
  414.     fixedName = removeDot(name)
  415.     fixedName = prepareName(fixedName, fixedMeshList)
  416.     fixedMeshList.append(fixedName)
  417.  
  418.     print "Writing mesh %s as %s..." % (name, fixedName)
  419.  
  420.     meshFileName = ("%s/%s.vib" % (meshPath, fixedName))
  421.     MESHFILE = open(meshFileName, "w")
  422.     MESHFILE.write("// Mesh Structure exported from Blender by bruteforce\n\n")
  423.     MESHFILE.write("Declare %s = Solid [\n" % fixedName)
  424.     VIBFILE.write("ReadArchive \"%s\"\n" % meshFileName)
  425.     VIBFILE.write("%s [\n" % fixedName)
  426.  
  427.     materials = meshObj.materials
  428.     vertices = mesh.vertices
  429.     vnormals = mesh.normals
  430.     texcoords = mesh.texcoords
  431.     abNormals = 0
  432.  
  433.     # get a list of materials for later
  434.     for material in materials:
  435.         try:
  436.             materialList.index(material)
  437.         except:
  438.             if material: materialList.append(material)
  439.  
  440.     # You have to add textures yourself
  441.     if mesh.texture:
  442.         VSFILE.write("// Mesh %s has UV Coords applied to it.  If you wish to add textures,\n" % name)
  443.         VSFILE.write("// please read the VirtauLight docs for more info on adding UV Textures\n\n")
  444.         print "Please read the VirtuaLight docs for adding UV Textures"
  445.  
  446.     # the j is to keep track what iteration I'm on in the
  447.     # "for face in faces" loop so I can make sure I'm on the
  448.     # right set of UV coords
  449.     j = 0
  450.     totalFaces = len(faces) - 1
  451.     for face in faces:
  452.         if face[3]: totalVerts = 4
  453.         else: totalVerts = 3
  454.  
  455.         # gets us a normalized face normal
  456.         if not face[4]:
  457.             normals = calcNormal(face, vertices, totalVerts - 3)
  458.             # if we have a divide by zero in normal calculation,
  459.             # then we absolutley have a stray vertex or two
  460.             if normals == "stray":
  461.                 totalFaces = totalFaces - 1
  462.                 abNormals = 1
  463.                 print "WARNING: stray vertices found"
  464.                 print "WARNING: output may not be as expected"
  465.                 continue
  466.  
  467.         # triangles
  468.         if not (totalVerts - 3):
  469.             MESHFILE.write("\tShape [TriangularPatch (")
  470.             for i in range(totalVerts):
  471.                 MESHFILE.write("(%s,%s,%s), " % (round(vertices[face[i]][0],r),
  472.                                                  round(vertices[face[i]][1],r),
  473.                                                  round(vertices[face[i]][2],r)))
  474.                 # use vertex normals if smoothed, else print face normal
  475.                 if face[4]:
  476.                     MESHFILE.write("(%s,%s,%s)" % (round(vnormals[face[i]][0],r),
  477.                                                    round(vnormals[face[i]][1],r),
  478.                                                    round(vnormals[face[i]][2],r)))
  479.                 else:
  480.                     MESHFILE.write("(%s,%s,%s)" % (round(normals[0],r),
  481.                                                    round(normals[1],r),
  482.                                                    round(normals[2],r)))
  483.                 # add texcoords, if any
  484.                 if texcoords:
  485.                     MESHFILE.write(" UV=%s,%s" % (round(texcoords[j][i][0],r),
  486.                                                   round(texcoords[j][i][1],r)))
  487.                 if i != totalVerts - 1: MESHFILE.write(", ")
  488.         # create triangle if face is QUAD
  489.         # So who's your daddy now?
  490.         else:
  491.             MESHFILE.write("\tShape [TriangularPatch (")
  492.             for i in range(totalVerts - 1):
  493.                 MESHFILE.write("(%s,%s,%s), " % (round(vertices[face[i]][0],r),
  494.                                                  round(vertices[face[i]][1],r),
  495.                                                  round(vertices[face[i]][2],r)))
  496.                 # use vertex normals if smoothed, else print face normal
  497.                 if face[4]:
  498.                     MESHFILE.write("(%s,%s,%s)" % (round(vnormals[face[i]][0],r),
  499.                                                    round(vnormals[face[i]][1],r),
  500.                                                    round(vnormals[face[i]][2],r)))
  501.                 else:
  502.                     MESHFILE.write("(%s,%s,%s)" % (round(normals[0],r),
  503.                                                    round(normals[1],r),
  504.                                                    round(normals[2],r)))
  505.                 # add texcoords, if any
  506.                 if texcoords:
  507.                     MESHFILE.write(" UV=%s,%s" % (round(texcoords[j][i][0],r),
  508.                                                   round(texcoords[j][i][1],r)))
  509.                 if i != totalVerts - 2:
  510.                     MESHFILE.write(", ")
  511.                 else:
  512.                     if materials and materials[face[5]]:
  513.                         fixedMatName = removeDot(materials[face[5]], 0)
  514.                         fixedMatName = prepareName(fixedMatName, materialList, 0)
  515.                         MESHFILE.write(") %s ]+\n" % fixedMatName)
  516.                     else:
  517.                         MESHFILE.write(") ]+\n")
  518.             MESHFILE.write("\tShape [TriangularPatch (")
  519.             for i in range(totalVerts - 1):
  520.                 I = i + 2
  521.                 if I > (totalVerts - 1): I = 0
  522.                 MESHFILE.write("(%s,%s,%s), " % (round(vertices[face[I]][0],r),
  523.                                                  round(vertices[face[I]][1],r),
  524.                                                  round(vertices[face[I]][2],r)))
  525.                 # use vertex normals if smoothed, else print face normal
  526.                 if face[4]:
  527.                     MESHFILE.write("(%s,%s,%s)" % (round(vnormals[face[I]][0],r),
  528.                                                    round(vnormals[face[I]][1],r),
  529.                                                    round(vnormals[face[I]][2],r)))
  530.                 else:
  531.                     MESHFILE.write("(%s,%s,%s)" % (round(normals[0],r),
  532.                                                    round(normals[1],r),
  533.                                                    round(normals[2],r)))
  534.                 # add texcoords, if any
  535.                 if texcoords:
  536.                     MESHFILE.write(" UV=%s,%s" % (round(texcoords[j][I][0],r),
  537.                                                   round(texcoords[j][I][1],r)))
  538.                 if I != 0: MESHFILE.write(", ")
  539.         # if the face has material, add it here
  540.         if materials and materials[face[5]]:
  541.             fixedMatName = removeDot(materials[face[5]], 0)
  542.             fixedMatName = prepareName(fixedMatName, materialList, 0)
  543.             MESHFILE.write(") %s ]" % fixedMatName)
  544.         else: MESHFILE.write(") ]")
  545.         # if faces still exist, csg them with (+)
  546.         if j == totalFaces: MESHFILE.write("\n")
  547.         elif j == totalFaces - 1 and abNormals: MESHFILE.write("\n")
  548.         else: MESHFILE.write("+\n")
  549.  
  550.         j = j + 1
  551.  
  552.     abNormals = 0
  553.  
  554.     # Prints out the final material
  555.     MESHFILE.write("]\n\n")
  556.     MESHFILE.close()
  557.  
  558.  
  559.     # I apply the transformations DIRECT, rather than using Blender's "loc, rot, size"
  560.     # because I was getting some weird ass results.  *shrug*
  561.     #VIBFILE.write("\tTransformationStack [\n")
  562.     VIBFILE.write("\tTransform (\n\t\t\t%s,%s,%s,%s," \
  563.                                  "\n\t\t\t%s,%s,%s,%s," \
  564.                                  "\n\t\t\t%s,%s,%s,%s," \
  565.                                  "\n\t\t\t%s,%s,%s,%s"  \
  566.                                  "\n\t\t)" % (
  567.                     round(meshObj.matrix[0][0],r),
  568.                     round(meshObj.matrix[0][1],r),
  569.                     round(meshObj.matrix[0][2],r),
  570.                     round(meshObj.matrix[0][3],r),
  571.                     round(meshObj.matrix[1][0],r),
  572.                     round(meshObj.matrix[1][1],r),
  573.                     round(meshObj.matrix[1][2],r),
  574.                     round(meshObj.matrix[1][3],r),
  575.                     round(meshObj.matrix[2][0],r),
  576.                     round(meshObj.matrix[2][1],r),
  577.                     round(meshObj.matrix[2][2],r),
  578.                     round(meshObj.matrix[2][3],r),
  579.                     round(meshObj.matrix[3][0],r),
  580.                     round(meshObj.matrix[3][1],r),
  581.                     round(meshObj.matrix[3][2],r),
  582.                     round(meshObj.matrix[3][3],r)))
  583.     #VIBFILE.write("\t]\n")
  584.     VIBFILE.write("]\n\n")
  585.  
  586.  
  587. #
  588. # material export
  589. #
  590. materialList.sort()
  591. for name in materialList:
  592.     # Check for "." in name, then make sure name is unique
  593.     fixedName = removeDot(name)
  594.     fixedName = prepareName(fixedName, fixedMatList)
  595.     fixedMatList.append(fixedName)
  596.     print "Writing material %s as %s..." % (name, fixedName)
  597.     material = Blender210.getMaterial(name)
  598.     VSFILE.write("Declare %s = Shader [ PlainSurface [\n" % fixedName)
  599.     VSFILE.write("\tColor '%s,%s,%s'\n" % (material.R, material.G, material.B))
  600.     if material.Emit >= 0.1:
  601.         VSFILE.write("\tKa %s\n" % material.Emit)
  602.     VSFILE.write("\tKd %s\n" % material.Ref)
  603.     VSFILE.write("\tKs (%s, '%s,%s,%s')\n" % (material.Spec, material.SpecR, material.SpecG, material.SpecB))
  604.     VSFILE.write("\t%sSpecularBRDF %s\n" % (specHighlight[specType], (-45*material.Hard)/254 + (45*255)/254))
  605.     VSFILE.write("\tKt (%s, %s, '%s,%s,%s')\n" % (1.0 - material.Alpha, 1.333, material.MirR, material.MirG, material.MirB))
  606.     VSFILE.write("\t]\n]\n\n")
  607.  
  608.  
  609. VIBFILE.close()
  610. VSFILE.close()
  611.  
  612. print "GI Blender... complete\n"
  613. sys.stdout.flush()
  614.